import bpy
from bpy.types import Panel #, Context, UILayout, NodesModifier, NodeGroupInput
from ...addon.naming import FluidLabNaming
from ..ui_module_panel import FLUIDLAB_ModulePanel
from ...libs.functions.get_common_vars import get_common_vars
from ...libs.functions.common_ui_elements import title_header, collapsable
from ...libs.functions.geometry_nodes import get_node_index_or_identifier_by as identifier
from bpy.app.translations import pgettext_iface as iface_


def get_count_of_point_cloud_points(ob):

    depsgraph = bpy.context.evaluated_depsgraph_get()
    
    # De esta manera solo funciona si hay Mesh data, ignora los point clouds:
    # ob_eval = ob.evaluated_get(depsgraph)
    # me = ob_eval.data
    # for k, v in me.attributes.items():
    #     if k != "position": # the keys is the named attributes (columns)
    #         continue
    #     return len(v.data)

    # De esta manera si funciona con los point clouds:
    for object_instance in depsgraph.object_instances:
        if not object_instance.is_instance:
            continue
        if object_instance.object.name != ob.name:
            continue
        for k, v in object_instance.object.data.attributes.items():
            if k != "position": # the keys is the named attributes (columns)
                continue
            total_points = len(v.data)
            return total_points
        

def single_or_multi(nodes, layout, GN_mod, grp_info_common_data, switch_node:str, single_node:str, single1:str, multi1:str, multi2:str, single_label:str, multi_label:str) -> None:

    node_switch = nodes.get(switch_node)
    if not node_switch:
        return

    node_inputs_switch = node_switch.inputs['Switch']
    node_toggle = node_inputs_switch.default_value

    if not node_toggle:
        # Single value
        if single_node is not None:
            
            single_node = nodes.get(single_node)
            if single_node:
                single_toggle = single_node.outputs[0]
                single = layout.row(align=True)
                single.prop(single_toggle, "default_value", text=single_label)
                toggle = single.row(align=True)
        else:
            if single1 is not None:
                single = layout.row(align=True)
                single.prop(GN_mod, f'["{identifier(*grp_info_common_data, single1, False)}"]', text=single_label)
                toggle = single.row(align=True)
    else:
        # Multiple values
        multi = layout.row(align=True)
        multi.prop(GN_mod, f'["{identifier(*grp_info_common_data, multi1, False)}"]', text=multi_label)
        multi.prop(GN_mod, f'["{identifier(*grp_info_common_data, multi2, False)}"]', text="")
        toggle = multi.row(align=True)

    toggle.scale_x = 0.35
    toggle.prop(node_inputs_switch, "default_value", text=" ", icon='TRIA_DOWN' if node_toggle else 'TRIA_LEFT')


class FLUIDLAB_PT_fluid_mesh_ui(Panel, FLUIDLAB_ModulePanel):
    fluidlab_section = 'MESH'
    bl_idname = "FLUIDLAB_PT_fluid_mesh_ui"
    bl_label = "Module"


    def draw(self, context):

        fluid_mesh, ui, toggles = get_common_vars(context, get_fluid_mesh=True, get_ui=True, get_toggles=True)
        # active_group = fluid_groups.active
        # emitters_list = active_group.emitters
        # active_emitter = emitters_list.active.emitter

        layout = self.layout
        layout.use_property_split = True
        layout.use_property_decorate = False

        col = layout.column(align=True)
        title_header(col, "Mesh")

        main_col = col.box().column(align=True)
        main_col.use_property_split = True
        main_col.use_property_decorate = False

        # -------------------------------------------------------------------------------
        # ## UI BASICA ##
        # ------------------------------------------------------------------------------- 
        if ui.ui_mode == 'BASIC':
            main_col.label(text="Hola Mundo Basico")

    
        # -------------------------------------------------------------------------------
        # ## UI AVANZADA ##
        # ------------------------------------------------------------------------------- 
        elif ui.ui_mode == 'ADVANCED':

            mesh_list_title = main_col.box().row(align=True)
            mesh_list_title.alignment = 'CENTER'
            mesh_list_title.label(text="List of meshes".title())

            main_col.template_list("FLUIDLAB_UL_draw_fluids_mesh", "", fluid_mesh, "list", fluid_mesh, "list_index", rows=3)

            buttons = main_col.row(align=True)
            buttons.scale_y = 1.3
            buttons.operator("fluidlab.add_gn_mesh", text="Add Mesh")

            # Settings del GN activo:
            if not fluid_mesh.is_void:
                
                active_mesh = fluid_mesh.active
                ob = active_mesh.ob
                if ob is not None:
                    
                    GN_mod = ob.modifiers.get(FluidLabNaming.GN_MESH_MOD)
                    
                    if GN_mod and ui.main_modules == 'MESH':

                        nodes = GN_mod.node_group.nodes

                        group_input = nodes.get("Group Input")
                        if group_input:
            
                            grp_info_common_data = ("identifier", "name", "outputs", group_input)

                            subsections = col.box().row(align=True)
                            subsections.use_property_split = False
                            subsections.scale_y = 1.3
                            subsections.prop(active_mesh.settings, "subsections", expand=True)

                            if active_mesh.settings.subsections == 'FLUID':

                                m_settings = collapsable(
                                    col,
                                    toggles,
                                    "mesh_settings",
                                    "Remesh Settings",
                                    'MOD_REMESH', # TOOL_SETTINGS
                                    align=True,
                                )
                                if m_settings:

                                    #-------------------------------------------------------------------------------------------
                                    # Mostrando las properties expuestas del GN:
                                    #-------------------------------------------------------------------------------------------
                                    
                                    # data comun entre las properties, para utilizar como argumentos del metodo identifier:

                                    lq_m_on_off = m_settings.row(align=True)
                                    lq_m_on_off.scale_y = 1.3
                                    prop_name = "Liquid Mesh ON/OFF"
                                    liquid_mesh_id = identifier(*grp_info_common_data, prop_name, False)

                                    liquid_mesh_toggle = GN_mod[liquid_mesh_id]
                                    lq_m_on_off.prop(GN_mod, f'["{liquid_mesh_id}"]', text=prop_name, toggle=True)
                                    lq_m_on_off.prop(GN_mod, f'["{liquid_mesh_id}"]', text="", toggle=True, icon='TRIA_DOWN' if liquid_mesh_toggle else 'TRIA_LEFT')
                                    
                                    if liquid_mesh_toggle:

                                        m_settings.separator()
                                        m_settings.prop(GN_mod, f'["{identifier(*grp_info_common_data, "Voxel Resolution", False)}"]', text="Voxel resolution")

                                        # m_settings.separator()
                                        min_max_row = m_settings.row(align=True)
                                        
                                        if active_mesh.settings.min_max_expand:
                                            min_max_row.prop(GN_mod, f'["{identifier(*grp_info_common_data, "Min", False)}"]', text="Min | Max")
                                            min_max_row.prop(GN_mod, f'["{identifier(*grp_info_common_data, "Max", False)}"]', text="")
                                        else:
                                            min_max_row.prop(active_mesh.settings, "min_max_value", text="Min/Max" )
            
                                        min_max_toggle = min_max_row.row(align=True)
                                        min_max_toggle.scale_x = 0.35
                                        min_max_expand_icon = 'TRIA_DOWN' if active_mesh.settings.min_max_expand else 'TRIA_LEFT'
                                        min_max_toggle.prop(active_mesh.settings, "min_max_expand", toggle=True, text=" ", icon=min_max_expand_icon)

                                        # m_settings.separator()
                                        split_axis = identifier(*grp_info_common_data, "SplitIterations", False)
                                        split_iterations_toggle = GN_mod[split_axis]
                                        row_split_iterations = m_settings.row(align=True)
                                        if split_iterations_toggle:
                                            row_split_iterations.prop(GN_mod, f'["{identifier(*grp_info_common_data, "Iterations X", False)}"]', text="Smooth XYZ")
                                            row_split_iterations.prop(GN_mod, f'["{identifier(*grp_info_common_data, "Iterations Y", False)}"]', text="")
                                            row_split_iterations.prop(GN_mod, f'["{identifier(*grp_info_common_data, "Iterations Z", False)}"]', text="")
                                            ri_toggle = row_split_iterations.row(align=True)
                                            ri_toggle.scale_x = 0.35
                                            ri_toggle.prop(GN_mod, f'["{split_axis}"]', text=" ", icon='TRIA_DOWN' if split_iterations_toggle else 'TRIA_LEFT')
                                        else:
                                            row_split_iterations.prop(GN_mod, f'["{identifier(*grp_info_common_data, "Iterations XYZ", False)}"]', text="Smooth XYZ")
                                            ri_toggle = row_split_iterations.row(align=True)
                                            ri_toggle.scale_x = 0.35
                                            ri_toggle.prop(GN_mod, f'["{split_axis}"]', text=" ", icon='TRIA_DOWN' if split_iterations_toggle else 'TRIA_LEFT')

                                        m_settings.prop(GN_mod, f'["{identifier(*grp_info_common_data, "Adaptivity", False)}"]', text="Adaptivity")
                                        # m_settings.prop(GN_mod, f'["{identifier(*grp_info_common_data, "Material", False)}"]', text="Material") # No me daja tal cual (lo pone gris)

                                        m_settings.separator()
            
                                        noise_block = m_settings.column(align=True)
                                        
                                        noise_id = identifier(*grp_info_common_data, "FinalNoiseToggle", False)
                                        noise = noise_block.row(align=True)
                                        noise.scale_y = 1.3

                                        noise_toggle = GN_mod[noise_id]
                                        noise.prop(GN_mod, f'["{noise_id}"]', text="Noise", toggle=True)
                                        noise.prop(GN_mod, f'["{noise_id}"]', text="", toggle=True, icon='TRIA_DOWN' if noise_toggle else 'TRIA_LEFT')
                                        
                                        if noise_toggle:
                                            
                                            noise_block.separator()
                                            noise_block.prop(GN_mod, f'["{identifier(*grp_info_common_data, "Noise Strenght", False)}"]', text="Strenght")
                                            noise_block.prop(GN_mod, f'["{identifier(*grp_info_common_data, "Scale", False)}"]', text="Scale")
                                            noise_block.prop(GN_mod, f'["{identifier(*grp_info_common_data, "Detail", False)}"]', text="Detail")
                                            noise_block.prop(GN_mod, f'["{identifier(*grp_info_common_data, "Roughness", False)}"]', text="Roughness")
                                            noise_block.prop(GN_mod, f'["{identifier(*grp_info_common_data, "Lacunarity", False)}"]', text="Lacunarity")
                                            noise_block.prop(GN_mod, f'["{identifier(*grp_info_common_data, "Distortion", False)}"]', text="Distortion")
                                            noise_block.separator()
                                            noise_block.prop(GN_mod, f'["{identifier(*grp_info_common_data, "Axis", False)}"]', text="Axis")
                                        
                                            noise_block.separator()

                                            # el vector del noise con la velocidad:
                                            velnoise_id = identifier(*grp_info_common_data, "VelNoiseSwitch", False)
                                            ui_velnoise = noise_block.row(align=True)
                                            ui_velnoise.scale_y = 1.3
                                            velnoise_toggle = GN_mod[velnoise_id]
                                            ui_velnoise.prop(GN_mod, f'["{velnoise_id}"]', text="Noise + Velocity", toggle=True)
                                            ui_velnoise.prop(GN_mod, f'["{velnoise_id}"]', text="", toggle=True, icon='TRIA_DOWN' if noise_toggle else 'TRIA_LEFT')
                                            if velnoise_toggle:
                                                noise_block.prop(GN_mod, f'["{identifier(*grp_info_common_data, "MapRange_From_Min", False)}"]', text="From Min")
                                                noise_block.prop(GN_mod, f'["{identifier(*grp_info_common_data, "MapRange_From_Max", False)}"]', text="From Max")
                                                noise_block.prop(GN_mod, f'["{identifier(*grp_info_common_data, "MapRange_To_Min", False)}"]', text="To Min")
                                                noise_block.prop(GN_mod, f'["{identifier(*grp_info_common_data, "MapRange_To_Max", False)}"]', text="To Max")

                                        
                                        # m_settings.separator()
                                        # flow_buttons = m_settings.grid_flow(row_major=True, columns=2, even_columns=False, even_rows=False, align=True)
                                        # flow_buttons.label(text="")
                                        # col_buttons = flow_buttons.column(align=True)
                                        
                                        # col_buttons.scale_y = 1.3
                                        # col_buttons.scale_x = 2.3

                                        # separated_meshes = col_buttons.row(align=True)
                                        # separated_muted = nodes['FirstRealizeInstances'].mute
                                        # separated_meshes.operator("fluidlab.gn_separate_meshes", depress=separated_muted, text="Separated Meshes")
                            
                            elif active_mesh.settings.subsections == 'GRAIN':

                                g_settings = collapsable(
                                    col,
                                    toggles,
                                    "grain_settings",
                                    "Grain Settings",
                                    'LIGHTPROBE_VOLUME',
                                    align=True,
                                )
                                if g_settings:
                                
                                    count_points = str(get_count_of_point_cloud_points(ob))
                                    if count_points != "None":
                                        feedback_points = "(Dinamic Value) Total Points: " + count_points
                                        g_settings.box().label(text=feedback_points, icon='INFO')
                                        g_settings.separator()

                                    g_toggle = g_settings.row(align=True)
                                    g_toggle.scale_y = 1.3
                                    g_on_off_id = identifier(*grp_info_common_data, "Grain OFF/ON", False)
                                    grain_toggle = GN_mod[g_on_off_id]

                                    g_toggle.prop(GN_mod, f'["{g_on_off_id}"]', text="Grain ON/OFF", toggle=True)
                                    g_toggle.prop(GN_mod, f'["{g_on_off_id}"]', text="", toggle=True, icon='TRIA_DOWN' if grain_toggle else 'TRIA_LEFT')

                                    
                                    if grain_toggle:

                                        g_settings.separator()

                                        # Points or Geometry:
                                        p_or_g = g_settings.row(align=True)
                                        p_or_g.scale_y = 1.3
                                        p_or_g.prop(active_mesh.settings, "p_or_g", text=" ", expand=True)

                                        g_settings.separator()

                                        # Si estamos en modo Points, Sphere Collection no tiene sentido porque es con los Geometry:
                                        if active_mesh.settings.p_or_g != '1':

                                            sph_c_toggle = g_settings.row(align=True)
                                            sph_c_toggle.scale_y = 1.3
                                            
                                            g_sph_c_id = identifier(*grp_info_common_data, "Grain Sphere / Collection", False)
                                            sph_c_toggle.prop(GN_mod, f'["{g_sph_c_id}"]', text="Sphere/Collection", toggle=True)
                                            if GN_mod[g_sph_c_id]:
                                                # g_settings.prop(GN_mod, f'["{identifier(*grp_info_common_data, "Collection Grains", False)}"]', text="Collection Grains") # No me daja tal cual (lo pone gris)
                                                g_settings.prop(active_mesh.settings, "collection_grains", text="Collection Grains")

                                            g_settings.separator()

                                        
                                        g_settings.prop(GN_mod, f'["{identifier(*grp_info_common_data, "Amount", False)}"]', text="Amount")
                                        
                                        g_min_max_size_row = g_settings.row(align=True)
                                        g_min_max_size_row.prop(GN_mod, f'["{identifier(*grp_info_common_data, "Min Size", False)}"]', text="Radius Min | Max")
                                        g_min_max_size_row.prop(GN_mod, f'["{identifier(*grp_info_common_data, "Max Size", False)}"]', text=" ")
                                        
                                        g_settings.prop(GN_mod, f'["{identifier(*grp_info_common_data, "Rot Min", False)}"]', text="Rotation Min")
                                        g_settings.prop(GN_mod, f'["{identifier(*grp_info_common_data, "Rot Max", False)}"]', text="Rotation Max")
                                        g_settings.prop(GN_mod, f'["{identifier(*grp_info_common_data, "Seed", False)}"]', text="Seed")

                                        # ExtraDots:
                                        # Solo en modo Points:
                                        if active_mesh.settings.p_or_g != '0':
                                        
                                            g_settings.separator()

                                            extra_dots_switcher = g_settings.row(align=True)
                                            extra_dots_switcher.scale_y = 1.3

                                            ed_switch_on_off_id = identifier(*grp_info_common_data, "ExtraDots Switch", False)
                                            ed_switch_on_off_toggle = GN_mod[ed_switch_on_off_id]

                                            extra_dots_switcher.prop(GN_mod, f'["{ed_switch_on_off_id}"]', text="Extra Dots ON/OFF", toggle=True)
                                            extra_dots_switcher.prop(GN_mod, f'["{ed_switch_on_off_id}"]', text="", toggle=True, icon='TRIA_DOWN' if ed_switch_on_off_toggle else 'TRIA_LEFT')

                                            if ed_switch_on_off_toggle:
                                                g_settings.separator()

                                                single_or_multi(
                                                                nodes, 
                                                                g_settings, 
                                                                GN_mod, 
                                                                grp_info_common_data,
                                                                switch_node="ExtraDots_DupliRand_Min_Max_Switch", 
                                                                # single_node="ExtraDots_DupliRand_MinMax_single",
                                                                single_node=None, 
                                                                single1="ExtraDots MinMax Single",
                                                                multi1="ExtreaDots DupliRand Min", 
                                                                multi2="ExtreaDots DupliRand Max", 
                                                                single_label="Copies", 
                                                                multi_label="Random Min | Max")

                                                g_settings.prop(GN_mod, f'["{identifier(*grp_info_common_data, "ExtraDots Amount Probability", False)}"]', text="Probability")
                                                
                                                
                                                # "Radius Min | Max":
                                                row_min_max = g_settings.row(align=True)
                                                row_min_max.prop(GN_mod, f'["{identifier(*grp_info_common_data, "ExtraDots Min Radius", False)}"]', text="Radius Min | Max")
                                                row_min_max.prop(GN_mod, f'["{identifier(*grp_info_common_data, "ExtraDots Max Radius", False)}"]', text=" ")
                                                
                                                # ExtraDots Separation:
                                                separation_switch = nodes.get("ExtraDots_separation_switcher")
                                                sep_inputs_switch = separation_switch.inputs['Switch']

                                                separation_multi = nodes.get("ExtraDots_separation_single")
                                                sep_outputs_single = separation_multi.outputs[0]

                                                separation_multi = nodes.get("ExtraDots_separation_multi")
                                                sep_inputs_multi_x = separation_multi.inputs[0]
                                                sep_inputs_multi_y = separation_multi.inputs[1]
                                                sep_inputs_multi_z = separation_multi.inputs[2]

                                                separation_toggle = sep_inputs_switch.default_value
                                                row_sep = g_settings.row(align=True)

                                                if separation_toggle:
                                                    row_sep.prop(sep_inputs_multi_x, "default_value", text="Separation XYZ")
                                                    row_sep.prop(sep_inputs_multi_y, "default_value", text="")
                                                    row_sep.prop(sep_inputs_multi_z, "default_value", text="")
                                                    sep_toggle = row_sep.row(align=True)
                                                    sep_toggle.scale_x = 0.35
                                                    sep_toggle.prop(sep_inputs_switch, "default_value", text=" ", icon='TRIA_DOWN' if separation_toggle else 'TRIA_LEFT')
                                                else:
                                                    row_sep.prop(sep_outputs_single, "default_value", text="Separation XYZ")
                                                    sep_toggle = row_sep.row(align=True)
                                                    sep_toggle.scale_x = 0.35
                                                    sep_toggle.prop(sep_inputs_switch, "default_value", text=" ", icon='TRIA_DOWN' if separation_toggle else 'TRIA_LEFT')
            
                                                g_settings.prop(GN_mod, f'["{identifier(*grp_info_common_data, "ExtraDots Probability Seed", False)}"]', text="Seed")

                                                
                                                # Fake Motion for Extra Dots:
                                                ########################################################################################
                                                g_settings.separator()

                                                fphisics_scale = nodes.get("ExtraDots FPhisics Scale")
                                                if fphisics_scale:
                                                    shocket_scale = identifier("identifier", "name", "inputs", fphisics_scale, "Scale", debug=False)
                                                    g_settings.prop(fphisics_scale.inputs[shocket_scale], "default_value", text="Motion Magnitude")
                                                
                                                fphisics_threshold = nodes.get("ExtraDots FPhisics Threshold")
                                                if fphisics_threshold:
                                                    g_settings.prop(fphisics_threshold.inputs[1], "default_value", text="Static Threshold")
                                                
                                                fphisics_n_scale = nodes.get("ExtraDots FPhisics Noise")
                                                if fphisics_n_scale:
                                                    g_settings.prop(fphisics_n_scale.inputs[2], "default_value", text="Noise Scale")
                                                
                                                g_settings.separator()
                                                # END Fake Motion for Extra Dots
                                                ########################################################################################

                                                ed_in_mesh_id = identifier(*grp_info_common_data, "ExtraDotsInMesh", False)
                                                g_settings.prop(GN_mod, f'["{ed_in_mesh_id}"]', text="Extra Dots in Mesh", toggle=True)